home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-11-19 | 24.9 KB | 770 lines | [TEXT/MPS ] |
- {
- File: Sample.p
-
- Contains: This is a simple application, based on the DTS traffic light example,
- that demonstrates how to use the Shared Library Manager. It puts the
- functionality of the traffic light window into a shared library and
- then uses that library from the client application.
-
- Copyright: © 1993-1994 by Apple Computer, Inc., all rights reserved.
-
- }
-
-
- PROGRAM Sample;
-
- USES
- MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, Traps, Strings, PasLibIntf,
- SampleLibrary, LibraryManager, LibraryManagerUtilities;
-
- CONST
- kSysEnvironsVersion = 1;
- kOSEvent = app4Evt; {event used by MultiFinder}
- kSuspendResumeMessage = 1; {high byte of suspend/resume event message}
- kResumeMask = 1; {bit of message field for resume vs. suspend}
- kNoEvents = 0; {no events mask}
-
- kMinHeap = 21 * 1024;
-
- kMinSpace = 8 * 1024;
-
- {kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions.}
- kExtremeNeg = -32768;
- kExtremePos = 32767 - 1; {required for old region bug}
-
- {The following constants are all resource IDs, corresponding to resources in Sample.r.}
- rMenuBar = 128; {application's menu bar}
- rAboutAlert = 128; {about alert}
- rUserAlert = 129; {error user alert}
-
- {The following constants are used to identify menus and their items. The menu IDs
- have an "m" prefix and the item numbers within each menu have an "i" prefix.}
- mApple = 128; {Apple menu}
- iAbout = 1;
-
- mFile = 129; {File menu}
- iNew = 1;
- iClose = 4;
- iQuit = 12;
-
- mEdit = 130; {Edit menu}
- iUndo = 1;
- iCut = 3;
- iCopy = 4;
- iPaste = 5;
- iClear = 6;
-
- kDITop = $0050;
- kDILeft = $0070;
-
- VAR
- {The "g" prefix is used to emphasize that a variable is global.}
-
- {gMac is used to hold the result of a SysEnvirons call. This makes
- it convenient for any routine to check the environment. It is
- global information, anyway.}
-
- gMac : SysEnvRec; {set up by Initialize}
-
- {gHasWaitNextEvent is set at startup, and tells whether the WaitNextEvent
- trap is available. If it is false, we know that we must call GetNextEvent.}
-
- gHasWaitNextEvent : BOOLEAN; {set up by Initialize}
-
- {gInBackground is maintained by our osEvent handling routines. Any part of
- the program can check it to find out if it is currently in the background.}
-
- gInBackground : BOOLEAN; {maintained by Initialize and DoEvent}
-
-
- (*————————————————————————————————————————————————————————————————————————————————————
- TrapAvailable
-
- Check to see if a given trap is implemented. This is only used by the initialize
- routine in this program, so we put it in the initialize segment.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Initialize}
- FUNCTION MyTrapAvailable(tNumber: INTEGER; tType: TrapType): BOOLEAN;
-
- BEGIN
- IF (tType = ToolTrap) &
- (gMac.machineType > envMachUnknown) &
- (gMac.machineType < envMacII) THEN BEGIN {it's a 512KE, Plus, or SE}
- tNumber := BAND(tNumber, $03FF);
- IF tNumber > $01FF THEN {which means the tool traps}
- tNumber := _Unimplemented; {only go to $01FF}
- END;
- MyTrapAvailable := NGetTrapAddress(tNumber, tType) <>
- NGetTrapAddress(_Unimplemented, tType);
- END; {MyTrapAvailable}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- IsDAWindow
-
- Check if a window belongs to a desk accessory
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- FUNCTION IsDAWindow(window: WindowPtr): BOOLEAN;
-
- BEGIN
- IF window = NIL THEN
- IsDAWindow := FALSE
- ELSE {DA windows have negative windowKinds}
- IsDAWindow := (WindowPeek(window)^.windowKind < 0);
- END; {IsDAWindow}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- IsAppWindow
-
- Check to see if a window belongs to the application.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- FUNCTION IsAppWindow(window: WindowPtr): BOOLEAN;
-
- BEGIN
- IF window = NIL THEN
- IsAppWindow := FALSE
- ELSE {application windows have windowKinds = userKind (8)}
- WITH WindowPeek(window)^ DO
- IsAppWindow := (windowKind = userKind);
- END; {IsAppWindow}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- AlertUser
-
- Display an alert that tells the user an error occured, then exit the program. This
- routine is used as an ultimate bail-out for serious errors that prohibit the cont-
- inuation of the application.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- PROCEDURE AlertUser;
-
- VAR
- itemHit : INTEGER;
- BEGIN
- SetCursor(arrow);
- itemHit := Alert(rUserAlert, NIL);
- ExitToShell;
- END; {AlertUser}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- DoCloseWindow
-
- Close a window. This handles desk accessory and application windows. Note the
- traffic library manager allocated the windowrecord for window, so disposing of
- the WindowRecord should be left upon the traffic light library.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- FUNCTION DoCloseWindow(window: WindowPtr) : BOOLEAN;
-
- BEGIN
-
- DoCloseWindow := TRUE;
- IF IsDAWindow(window) THEN
- CloseDeskAcc(WindowPeek(window)^.windowKind)
- ELSE IF IsAppWindow(window) THEN
- FreeTrafficLight; { give a chance for our library to clean }
-
-
- END; {DoCloseWindow}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- UnLoadTrafficLightLibrary
-
- unload the traffic light object and free the memory allocated by our library
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- PROCEDURE UnLoadTrafficLightLibrary;
- VAR
- err : OSErr;
- str : Str255;
- pstr : StringPtr;
- BEGIN
-
- (* need to convert the string from pascal to C, since FunctionSetID is a C string *)
-
- pstr := PLStrCpy(str, kTrafficLightFunctionSet);
- P2CStrProc(@str[0]);
- err:= UnloadFunctionSet(@str[0]);
- { A library loaded with LoadFunctionSet() is not
- unloaded until all objects from the library
- are deleted and an UnloadFunctionSet() call is
- made to balance each LoadFunctionSet() call }
- CleanupLibraryManager; { we are done with library manager }
- ExitToShell;
-
- END; { UnLoadTrafficLightLibrary }
-
- (*————————————————————————————————————————————————————————————————————————————————————
- LoadTrafficLightLibrary
-
- load the traffic light library. This library automatically creates a window and
- attach a traffic menu to our current menu.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Initialize}
- PROCEDURE LoadTrafficLightLibrary( window : WindowPtr );
- VAR
- loaded : BOOLEAN;
- str : Str255;
- pstr : StringPtr;
- BEGIN
-
- (* always initilize the library manager before any Shared Library calls. This
- creates a local instance of TLibraryManager for accessing our libraries. *)
-
- IF( InitLibraryManager( 0, { we don't need memory in our local pool }
- kCurrentZone, { use application zone = current zone }
- kNormalMemory ) { default memory type, no VM stuff }
- <> kNoError ) THEN
- AlertUser; { failed to load the library, tell user }
-
- (* need to convert the string from pascal to C, since FunctionSetID is a C string *)
- pstr := PLStrCpy(str, kTrafficLightFunctionSet);
- P2CStrProc(@str[0]);
-
- (* make sure the library is available before initializing trafficlight(via LoadFunctionSet) *)
- loaded := LoadFunctionSet(@str[0], TRUE) = kNoError;
- IF( loaded ) THEN BEGIN {if loaded continue}
- IF ( NewTrafficLight <> noErr ) THEN{ initialize our trafficlight shared library }
- AlertUser; { !oh well, we tried }
- END
- ELSE
- AlertUser;
-
- END; {LoadTrafficLightLibrary}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- Initialize
-
- Set up the whole world, including global variables, Toolbox managers,
- and menus. Sample is going to create its window, and traffic menu through its
- traffic library, using the shared library manager(Nahhhh...). The Library auto-
- matically create a window, attach a menu and draws the traffic light.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Initialize}
- PROCEDURE Initialize;
-
- VAR
- menuBar : Handle;
- window : WindowPtr;
- ignoreError : OSErr;
- total, contig : LongInt;
- ignoreResult : BOOLEAN;
- event : EventRecord;
- count : INTEGER;
-
- BEGIN
- gInBackground := FALSE;
-
- InitGraf(@thePort);
- InitFonts;
- InitWindows;
- InitMenus;
- TEInit;
- InitDialogs(NIL);
- InitCursor;
-
- {This next bit of code is necessary to allow the default button of our
- alert be outlined }
-
- FOR count := 1 TO 3 DO
- ignoreResult := EventAvail(everyEvent, event);
-
- {Ignore the error returned from SysEnvirons; even if an error occurred,
- the SysEnvirons glue will fill in the SysEnvRec. You can save a redundant
- call to SysEnvirons by calling it after initializing AppleTalk.}
-
- ignoreError := SysEnvirons(kSysEnvironsVersion, gMac);
-
- {Make sure that the machine has at least 128K ROMs. If it doesn't, exit.}
-
- IF gMac.machineType < 0 THEN AlertUser;
-
- {Move MyTrapAvailable call to after SysEnvirons so that we can tell
- in MyTrapAvailable if a tool trap value is out of range.}
-
- gHasWaitNextEvent := MyTrapAvailable(_WaitNextEvent, ToolTrap);
-
- {We used to make a check for memory at this point by examining ApplLimit,
- ApplicationZone, and StackSpace and comparing that to the minimum size we told
- MultiFinder we needed. This did not work well because it assumed too much about
- the relationship between what we asked MultiFinder for and what we would actually
- get back, as well as how to measure it. Instead, we will use an alternate
- method comprised of two steps.}
-
- {It is better to first check the size of the application heap against a value
- that you have determined is the smallest heap the application can reasonably
- work in. This number should be derived by examining the size of the heap that
- is actually provided by MultiFinder when the minimum size requested is used.
- The derivation of the minimum size requested from MultiFinder is described
- in Sample.h. The check should be made because the preferred size can end up
- being set smaller than the minimum size by the user. This extra check acts to
- insure that your application is starting from a solid memory foundation.}
-
- IF ORD(GetApplLimit) - ORD(ApplicationZone) < kMinHeap THEN AlertUser;
-
- {Next, make sure that enough memory is free for your application to run. It
- is possible for a situation to arise where the heap may have been of required
- size, but a large scrap was loaded which left too little memory. To check for
- this, call PurgeSpace and compare the result with a value that you have determined
- is the minimum amount of free memory your application needs at initialization.
- This number can be derived several different ways. One way that is fairly
- straightforward is to run the application in the minimum size configuration
- as described previously. Call PurgeSpace at initialization and examine the value
- returned. However, you should make sure that this result is not being modified
- by the scrap's presence. You can do that by calling ZeroScrap before calling
- PurgeSpace. Make sure to remove that call before shipping, though.}
-
- PurgeSpace(total, contig);
- IF total < kMinSpace THEN AlertUser;
-
- menuBar := GetNewMBar(rMenuBar); {read menus into menu bar}
- IF menuBar = NIL THEN AlertUser;
- SetMenuBar(menuBar); {install menus}
- DisposeHandle(menuBar);
- AppendResMenu(GetMenuHandle(mApple), 'DRVR'); {add DA names to Apple menu}
- DrawMenuBar;
-
- LoadTrafficLightLibrary( window ); {Load trafficlight shared library}
-
- END; {Initialize}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- Terminate
-
- Cleanup the application and exits. Close all of the windows, and cleanup our
- library. We replace the ExitToShell by UnLoadTrafficLightLibrary so we get a
- chance to unload the library and cleanup the library manager.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
-
- {$S Main}
- PROCEDURE Terminate;
-
- VAR
- aWindow : WindowPtr;
- closed : BOOLEAN;
-
- BEGIN
- closed := TRUE;
- REPEAT
- aWindow := FrontWindow; {get the current front window}
- IF aWindow <> NIL THEN
- closed := DoCloseWindow(aWindow); {close this window}
- UNTIL (NOT closed) | (aWindow = NIL); {do all windows}
- IF closed THEN
- UnLoadTrafficLightLibrary; {exit if no cancellation}
- END; {Terminate}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- AdjustMenus
-
- Enable and disable menus based on the current state. The user can only select en-
- abled menu items. We set up all the menu items before calling MenuSelect or MenuKey,
- since these are the only times that a menu item can be selected. Note that MenuSelect
- is also the only time the user will see menu items. This approach to deciding what
- enable/disable state a menu item has the advantage of concentrating all the decision-
- making in one routine, as opposed to being spread throughout the application. Other
- application designs may take a different approach that may or may not be just as valid.}
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- PROCEDURE AdjustMenus;
-
- VAR
- window : WindowPtr;
- menu : MenuHandle;
-
- BEGIN
- window := FrontWindow;
-
- menu := GetMenuHandle(mFile);
- IF IsDAWindow(window) THEN {we can allow desk accessories to be closed from the menu}
- EnableItem(menu, iClose)
- ELSE
- DisableItem(menu, iClose); {but not our traffic light window}
-
- menu := GetMenuHandle(mEdit);
- IF IsDAWindow(window) THEN BEGIN {a desk accessory might need the edit menu}
- EnableItem(menu, iUndo);
- EnableItem(menu, iCut);
- EnableItem(menu, iCopy);
- EnableItem(menu, iPaste);
- EnableItem(menu, iClear);
- END ELSE BEGIN {but we know we do not}
- DisableItem(menu, iUndo);
- DisableItem(menu, iCut);
- DisableItem(menu, iCopy);
- DisableItem(menu, iClear);
- DisableItem(menu, iPaste);
- END;
-
- (* Since our library takes also care of its own menu, we call it through the Function-
- set AdustTrafficMenus *)
-
- AdjustTrafficLightMenus( IsAppWindow(window) );
-
- END; {AdjustMenus}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- DoMenuCommand
-
- This is called when an item is chosen from the menu bar( after calling MenuSelect
- or MenuKey). It performs the right operation for each command. It is good to have
- both the result of MenuSelect and MenuKey go to one routine like this to keep
- everything organized.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- PROCEDURE DoMenuCommand(menuResult: LONGINT);
-
- VAR
- menuID : INTEGER; {the resource ID of the selected menu}
- menuItem : INTEGER; {the item number of the selected menu}
- itemHit : INTEGER;
- savedrefnum : INTEGER;
- daName : Str255;
- daRefNum : INTEGER;
- handledByDA : BOOLEAN;
- ignore : BOOLEAN;
- BEGIN
-
- menuID := HighWord(menuResult); {use built-ins (for efficiency)...}
- menuItem := LowWord(menuResult);{to get menu item number and menu number}
-
- CASE menuID OF
- mApple:
- CASE menuItem OF
- iAbout: {bring up alert for About}
- itemHit := Alert(rAboutAlert, NIL);
- OTHERWISE BEGIN {all non-About items in this menu are DAs}
- GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
- daRefNum := OpenDeskAcc(daName);
- END;
- END;
- mFile:
- CASE menuItem OF
- iClose:
- ignore := DoCloseWindow(FrontWindow); {we don't care if cancelled}
- iQuit:
- Terminate;
- END;
- mEdit: {call SystemEdit for DA editing & MultiFinder}
- handledByDA := SystemEdit(menuItem-1); {since we don't do any editing}
- mLight:
- BEGIN
- (* now its time to adjust our shared library menus *)
- DoTrafficLightMenuCommand( menuItem );
- END;
- END;
- HiliteMenu(0); {unhighlight what MenuSelect (or MenuKey) hilited}
- END; {DoMenuCommand}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- DrawWindow
-
- The draw window is reduced to a single call to our library. Our library is res-
- ponsible for drawing the traffic light.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- PROCEDURE DrawWindow(window: WindowPtr);
-
- BEGIN
-
- DrawLight; { Draw traffic light through library}
-
- END; {DrawWindow}
-
-
- (*————————————————————————————————————————————————————————————————————————————————————
- DoContentClick
-
- This is called when a mouse-down event occurs in the content of a window.
- Other applications might want to call FindControl, TEClick, etc., to
- further process the click.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
- {$S Main}
- PROCEDURE DoContentClick(window: WindowPtr; event: EventRecord);
-
- BEGIN
-
- (* Here we are going to toggle the traffic light by getting the previous state
- and inverting it to new state. All the calls are going through FunctionSet *)
-
- SetLightState( NOT GetLightState );
-
- END; {DoContentClick}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- DoUpdate
-
- This is called when an update event is received for a window.
- It calls DrawWindow to draw the contents of an application window.
- As an effeciency measure that does not have to be followed, it
- calls the drawing routine only if the visRgn is non-empty. This
- will handle situations where calculations for drawing or drawing
- itself is very time-consuming.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- PROCEDURE DoUpdate(window: WindowPtr);
-
- BEGIN
- IF IsAppWindow(window) THEN BEGIN
- BeginUpdate(window); {sets up the visRgn, clears updateRgn}
- IF NOT EmptyRgn(window^.visRgn) THEN {draw if updating needs to be done}
- DrawWindow(window);
- EndUpdate(window); {restores the visRgn}
- END;
- END; {DoUpdate}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- DoActivate
-
- Responsible for activating and deactivating window and its contents.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- PROCEDURE DoActivate(window: WindowPtr; becomingActive: BOOLEAN);
-
- BEGIN
- IF IsAppWindow(window) THEN
- IF becomingActive THEN
- {do whatever you need to at activation}
- ELSE
- {do whatever you need to at deactivation};
- END; {DoActivate}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- GetGlobalMouse
-
- Get the global coordinates of the mouse. The coordinate of the mouse is used to
- adjust the cursor accordingly.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
-
- {$S Main}
- PROCEDURE GetGlobalMouse(VAR mouse: Point);
-
- VAR
- event : EventRecord;
-
- BEGIN
- IF OSEventAvail(kNoEvents, event) THEN; {we aren't interested in any events}
- mouse := event.where; {just the mouse position}
- END;
-
- (*————————————————————————————————————————————————————————————————————————————————————
- AdjustCursor
-
- Change the cursor's shape, depending on its position. This also calculates the
- region where the current cursor resides (for WaitNextEvent). If the mouse is ever
- outside of that region, an event is generated, causing this routine to be called.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- PROCEDURE AdjustCursor(mouse: Point; region: RgnHandle);
-
- VAR
- window : WindowPtr;
- arrowRgn : RgnHandle;
- plusRgn : RgnHandle;
- globalPortRect : Rect;
-
-
- BEGIN
- window := FrontWindow; {we only adjust the cursor when we are in front}
- IF (NOT gInBackground) AND (NOT IsDAWindow(window)) THEN BEGIN
- {calculate regions for different cursor shapes}
- arrowRgn := NewRgn;
- plusRgn := NewRgn;
-
- {start with a big, big rectangular region}
- {1.01 - changed to kExtremeNeg and kExtremePos for consistency}
- SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg,
- kExtremePos, kExtremePos);
-
- {calculate plusRgn}
- IF IsAppWindow(window) THEN BEGIN
- SetPort(window); {make a global version of the portRect}
- SetOrigin(-window^.portBits.bounds.left, -window^.portBits.bounds.top);
- globalPortRect := window^.portRect;
- RectRgn(plusRgn, globalPortRect);
- SectRgn(plusRgn, window^.visRgn, plusRgn);
- SetOrigin(0, 0);
- END;
-
- {subtract other regions from arrowRgn}
- DiffRgn(arrowRgn, plusRgn, arrowRgn);
-
- {change the cursor and the region parameter}
- IF PtInRgn(mouse, plusRgn) THEN BEGIN
- SetCursor(GetCursor(plusCursor)^^);
- CopyRgn(plusRgn, region);
- END ELSE BEGIN
- SetCursor(arrow);
- CopyRgn(arrowRgn, region);
- END;
-
- {get rid of our local regions}
- DisposeRgn(arrowRgn);
- DisposeRgn(plusRgn);
- END;
- END; {AdjustCursor}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- DoEvent
-
- Do the right thing for an event. Determine what kind of event it is, and call the
- appropriate routine.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- PROCEDURE DoEvent(event: EventRecord);
-
- VAR
- part, err : INTEGER;
- window : WindowPtr;
- hit : BOOLEAN;
- key : CHAR;
- aPoint : Point;
-
- BEGIN
- CASE event.what OF
- mouseDown: BEGIN
- part := FindWindow(event.where, window);
- CASE part OF
- inMenuBar: BEGIN {process the menu command}
- AdjustMenus;
- DoMenuCommand(MenuSelect(event.where));
- END;
- inSysWindow: {let the system handle the mouseDown}
- SystemClick(event, window);
- inContent:
- IF window <> FrontWindow THEN BEGIN
- SelectWindow(window);
- {DoEvent(event);} {use this line for "do first click"}
- END ELSE
- DoContentClick(window, event);
- inDrag: {pass screenBits.bounds to get all gDevices}
- DragWindow(window, event.where, screenBits.bounds);
- inGrow:;
- inZoomIn, inZoomOut:;
- END;
- END;
- keyDown, autoKey: BEGIN {check for menukey equivalents}
- key := CHR(BAnd(event.message, charCodeMask));
- IF BAnd(event.modifiers, cmdKey) <> 0 THEN {Command key down}
- IF event.what = keyDown THEN BEGIN
- AdjustMenus; {enable/disable/check menu items properly}
- DoMenuCommand(MenuKey(key));
- END;
- END; {call DoActivate with the window and...}
- activateEvt: {TRUE for activate, FALSE for deactivate}
- DoActivate(WindowPtr(event.message), BAnd(event.modifiers, activeFlag) <> 0);
- updateEvt: {call DoUpdate with the window to update}
- DoUpdate(WindowPtr(event.message));
- {1.01 - It is not a bad idea to at least call DIBadMount in response
- to a diskEvt, so that the user can format a floppy.}
- diskEvt:
- IF HighWord(event.message) <> noErr THEN BEGIN
- SetPt(aPoint, kDILeft, kDITop);
- err := DIBadMount(aPoint, event.message);
- END;
- kOSEvent:
- CASE BAnd(BRotL(event.message, 8), $FF) OF {high byte of message}
- kSuspendResumeMessage: BEGIN
- gInBackground := BAnd(event.message, kResumeMask) = 0;
- DoActivate(FrontWindow, NOT gInBackground);
- END;
- END;
- END;
- END; {DoEvent}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- EventLoop
-
- Get events forever, and handle them by calling DoEvent. Get the events by calling
- WaitNextEvent, if it's available, otherwise by calling GetNextEvent. Also call
- AdjustCursor each time through the loop.
-
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- {$S Main}
- PROCEDURE EventLoop;
-
- VAR
- cursorRgn : RgnHandle;
- gotEvent : BOOLEAN;
- event : EventRecord;
- mouse : Point;
-
- BEGIN
- cursorRgn := NewRgn; {we’ll pass WNE an empty region the 1st time thru}
- REPEAT
- IF gHasWaitNextEvent THEN BEGIN {put us 'asleep' forever under MultiFinder}
- GetGlobalMouse(mouse); {since we might go to sleep}
- AdjustCursor(mouse, cursorRgn);
- gotEvent := WaitNextEvent(everyEvent, event, MAXLONGINT, cursorRgn);
- END ELSE BEGIN
- SystemTask; {must be called if using GetNextEvent}
- gotEvent := GetNextEvent(everyEvent, event);
- END;
- IF gotEvent THEN BEGIN
- AdjustCursor(event.where, cursorRgn); {make sure we have the right cursor}
- DoEvent(event);
- END;
- {If you are using modeless dialogs that have editText items,
- you will want to call IsDialogEvent to give the caret a chance
- to blink, even if WNE/GNE returned FALSE. However, check FrontWindow
- for a non-NIL value before calling IsDialogEvent.}
- UNTIL FALSE; {loop forever; we quit through an ExitToShell}
- END; {EventLoop}
-
- (*————————————————————————————————————————————————————————————————————————————————————
- _DataInit
-
- This routine is part of the MPW runtime library. This external reference to it
- is done so that we can unload its segment, %A5Init.
- ————————————————————————————————————————————————————————————————————————————————————*)
-
- PROCEDURE _DataInit; EXTERNAL;
-
- {$S Main}
- BEGIN
- UnloadSeg(@_DataInit); {note that _DataInit must not be in Main!}
-
- MaxApplZone; {expand the heap so code segments load at the top}
-
- Initialize; {initialize the program}
- UnloadSeg(@Initialize); {note that Initialize must not be in Main!}
-
- EventLoop; {call the main event loop}
- END.
-